package net.cathackers.devel.scmp.factories;

import java.io.File;

import net.cathackers.devel.exceptions.CATException;
import net.cathackers.devel.scmp.auth.backends.LDAPAuthenticatorBackend;
import net.cathackers.devel.scmp.auth.backends.MySQLAuthenticatorBackend;
import net.cathackers.devel.scmp.auth.impl.AuthenticatorProxyImpl;
import net.cathackers.devel.scmp.auth.impl.LocalUserProfile;
import net.cathackers.devel.scmp.auth.interfaces.Authenticator;
import net.cathackers.devel.scmp.auth.interfaces.IdentityManager;
import net.cathackers.devel.scmp.auth.interfaces.UserProfile;
import net.cathackers.devel.scmp.chat.backend.mysql.MySQLOfflineStoreBackend;
import net.cathackers.devel.scmp.chat.backends.MySQLRosterBackend;
import net.cathackers.devel.scmp.chat.impl.ChatConfigurationImpl;
import net.cathackers.devel.scmp.chat.impl.XMPPChatManagerImpl;
import net.cathackers.devel.scmp.chat.impl.xmpp.iqcomponent.roster.RosterSubscriptionManagerImpl;
import net.cathackers.devel.scmp.chat.impl.xmpp.messageComponent.OfflineMessageStore;
import net.cathackers.devel.scmp.chat.impl.xmpp.messageComponent.OfflineMessageStoreImpl;
import net.cathackers.devel.scmp.chat.interfaces.ChatConfiguration;
import net.cathackers.devel.scmp.chat.interfaces.ChatManager;
import net.cathackers.devel.scmp.chat.interfaces.RosterBackend;
import net.cathackers.devel.scmp.chat.interfaces.RosterSubscriptionManager;
import net.cathackers.devel.scmp.config.impl.AuthenticatorDBConfig;
import net.cathackers.devel.scmp.config.impl.OfflineStoreConfig;
import net.cathackers.devel.scmp.config.impl.RosterDBConfig;
import net.cathackers.devel.scmp.config.impl.XMLLDAPConfig;
import net.cathackers.devel.scmp.config.interfaces.AuthConfig;
import net.cathackers.devel.scmp.impl.LocalCoreSwitch;
import net.cathackers.devel.scmp.interfaces.CoreSwitch;
import net.cathackers.devel.scmp.xmpp.XMPPConfiguration;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;


public class SCMPFactory {
    private static volatile String		lock_          		= "Hello Locking";
    private static volatile String		baseConfigDir_		= "config";	 	
    private static volatile IdentityManager 	identityManager_	= null;
    private static volatile ChatManager 	chatManager_ 		= null;
    private static volatile Logger 	        rootLogger_    		= null;
    private static volatile Authenticator   	authenticator_ 		= null;
    private static volatile OfflineMessageStore   offlineStore_  	= null;
    private static volatile Level           	rootLogLevel_   	= Level.DEBUG;    // General
    private static volatile RosterBackend   	rosterbackend_		= null;
    private static volatile ChatConfiguration 	chatConfiguration_	= null;
    private static volatile String 		domainName_ 		= null;
    private static volatile XMPPConfiguration	xmppConf_		= null;
    private static volatile RosterSubscriptionManager	rosterManager_	= null;
    // logging level
    // for all
    // logging.
    private static volatile CoreSwitch      coreSwitch_;

    static {
        rootLogger_ = getLogger(SCMPFactory.class);
        rootLogger_.setLevel(rootLogLevel_);
        BasicConfigurator.configure();
        rootLogger_.debug("Logger Init.");
    }

    /**
     * methods here should have been synchronized, but because of the bad
     * performance impact of being synchronized, I'll use the Double-Checked
     * Locking mechanism here with volatile member to avoid the situation
     * described here
     * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
     */

    public static Logger getLogger(Object parentObject) {
        String className = parentObject.getClass().getSimpleName();
        Logger tmp = Logger.getLogger(className);
        tmp.setLevel(rootLogLevel_);
        return tmp;
    }

    public static IdentityManager getIdentityManager() {
        // not real implementation
        return identityManager_;
    }

    public static UserProfile getUserProfile(String id, IdentityManager backend) {
        // Stub, not real implementation
        return new LocalUserProfile(id, backend);
    }

//    public static DBConfig getDBConfig() {
//        if (dbConfig_ == null) {
//            synchronized (lock_) {
//                if (dbConfig_ == null) {
//                    Logger logger = getLogger("SCMPFactory");
//                    logger.debug("Loading database configuration...");
//                    dbConfig_ = new XMLDBConfig();
//                }
//            }
//        }
//        return dbConfig_;
//
//    }
    
    /**
     * this method should have been synchronized, but because of the bad
     * performance impact of being synchronized, I'll use the Double-Checked
     * Locking mechanism here with volatile member to avoid the situation
     * described here
     * http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
     */
    public static ChatManager getChatManager() {
	if (chatManager_ == null) {
	    synchronized (lock_) {
		if (chatManager_ == null) {
		    chatManager_ = new XMPPChatManagerImpl();
		    try {
			chatManager_.initialize();
		    } catch (CATException ex) {
			ex.printStackTrace();
		    }
		}
	    }
	}
	return chatManager_;
    }
    public static Authenticator getAuthenticator() {
        if (authenticator_ == null) {
            synchronized (lock_) {
                if (authenticator_ == null) {
                    String configPath = baseConfigDir_ + File.separator +"authConfig.xml";
                    Logger logger = getLogger("SCMPFactory");
                    logger.debug("Loading Authentication Backend...");
                    // Hackish
                    AuthConfig config = new XMLLDAPConfig(configPath);
                    Authenticator authBackend;
                    if (config.getAuthType().equalsIgnoreCase("mysql")) {
                	config = new AuthenticatorDBConfig(configPath);
                	authBackend = new MySQLAuthenticatorBackend((AuthenticatorDBConfig)config);
                    } else if (config.getAuthType().equalsIgnoreCase("ldap")) {
                	authBackend = new LDAPAuthenticatorBackend((XMLLDAPConfig)config);
                    } else {
                	throw new CATException("Invalid authType in configuration file<" + config.getAuthType() + ">");
                    }
                    authenticator_ = new AuthenticatorProxyImpl(authBackend);
                }
            }
        }
        return authenticator_;
    }
    
    public static ChatConfiguration getConfiguration() {
	if (chatConfiguration_ == null) {
	    synchronized (lock_) {
		if (chatConfiguration_ == null) {
		    String configPath = baseConfigDir_ + File.separator + "server.xml";
		    chatConfiguration_ = new ChatConfigurationImpl(configPath);
		}
	    }
	}
	return chatConfiguration_;
    }
    
    public static CoreSwitch getCoreSwitch() {
        if (coreSwitch_ == null) {
            synchronized (lock_) {
                if (coreSwitch_ == null) {
                    // TODO: add CoreSwitchBackend initialization here.
                    coreSwitch_ = new LocalCoreSwitch(null);
                }
            }
        }
        return coreSwitch_;
    }
    
    public static XMPPConfiguration getXMPPConfiguration() {
        if (xmppConf_ == null) {
            synchronized (lock_) {
                if (xmppConf_ == null) {
                    // TODO should get data from configuration file...
                    xmppConf_ = new XMPPConfiguration(baseConfigDir_ + File.separator + "xmppConfig.xml");
                }
            }
        }
        return xmppConf_;
    }
    
    public static OfflineMessageStore getOfflineMessageStore() {
	if(offlineStore_ == null) {
	    synchronized(lock_) {
		if(offlineStore_ == null) {
                    Logger logger = getLogger("SCMPFactory");
                    logger.debug("Loading Offline Messages Store...");
		    MySQLOfflineStoreBackend backend = new MySQLOfflineStoreBackend(new OfflineStoreConfig(baseConfigDir_ + File.separator + "offlineConfig.xml"));
		    
		    offlineStore_ = new OfflineMessageStoreImpl(backend);
		}
		
	    }
	}
	return offlineStore_;
    }
    
    
    public static RosterBackend getRosterBackend(){
	if	(null == rosterbackend_){
	    synchronized(lock_) {
		if (null == rosterbackend_) {
		    String configPath = baseConfigDir_ + File.separator + "roster.xml";
		    rosterbackend_ = new MySQLRosterBackend(new RosterDBConfig(configPath)); 
		}
	    }  
	}
	return rosterbackend_;
    }
    
    public static RosterSubscriptionManager getRosterSubscriptionManager() {
        if (rosterManager_ == null) {
            synchronized (lock_) {
                if (rosterManager_ == null) {
                    // TODO: add CoreSwitchBackend initialization here.
                    rosterManager_ = new RosterSubscriptionManagerImpl();
                }
            }
        }
        return rosterManager_;
    }
}
